package cn.shop.front.async;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.shop.front.entity.payModule.NotifyReq;
import cn.shop.front.mapper.FrontUserMapper;
import cn.shop.front.service.PromotionsService;
import cn.shop.transcation.backPaymentChannelModule.entity.BackPaymentChannel;
import cn.shop.transcation.detail.entity.FundDetail;
import cn.shop.transcation.detail.mapper.FundDetailMapper;
import cn.shop.transcation.frontUserModule.FrontUser;
import cn.shop.transcation.order.entity.OrderReward;
import cn.shop.transcation.order.mapper.OrderRewardMapper;
import cn.shop.transcation.promotionsModule.PrizeRule;
import cn.shop.transcation.promotionsModule.Promotions;
import cn.shop.transcation.promotionsModule.mapper.PrizeRuleMapper;
import cn.shop.transcation.rechargerecord.entity.Record;
import cn.shop.transcation.rechargerecord.mapper.RecordMapper;
import cn.shop.utils.constant.PromotionsConstant;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.List;

import static cn.shop.utils.constant.SystemSettingConstant.*;

/**
 * @author jzw
 * @since 2021-12-21 10:28
 */
@Component
@Slf4j
public class ProcessOrderAsync {

	@Resource
	private FrontUserMapper frontUserMapper;

	@Resource
	private RecordMapper recordMapper;

	@Resource
	private FundDetailMapper fundDetailMapper;
	@Resource
	private PromotionsService promotionsService;
	@Resource
	private OrderRewardMapper rewardMapper;
	@Resource
	private PrizeRuleMapper prizeRuleMapper;

	@Async("taskExecutor")
	public void processOrder(NotifyReq payCallback, Record record, BackPaymentChannel channel, String alias) {
		/*if (channel.getType() == RechargeSolution.UPAY_PAYMENT) {
			Promotions promotions = promotionsService.getOne(Wrappers.<Promotions>lambdaQuery()
					.eq(Promotions::getKey, PromotionsConstant.PRIZE_POOL));
			if (promotions.getEnable() && NumberUtil.isGreater(promotions.getPrizePool(), BigDecimal.ZERO)) {
				BigDecimal rate = record.getAmount().subtract(record.getActualAmount());
				boolean isSuccess = promotionsService.update(Wrappers.<Promotions>lambdaUpdate()
						.setSql("prize_pool = prize_pool - " + rate)
						.eq(Promotions::getId, 1)
						.gt(Promotions::getPrizePool, BigDecimal.ZERO));
				if (isSuccess) {
					promotions = promotionsService.getOne(Wrappers.<Promotions>lambdaQuery()
							.eq(Promotions::getKey, PromotionsConstant.PRIZE_POOL));
					BigDecimal actualAmount = NumberUtil.add(record.getActualAmount(), rate);
					if (NumberUtil.isLess(promotions.getPrizePool(), BigDecimal.ZERO)) { //奖池金额小于0
						if (NumberUtil.isLess(promotions.getPrizePool().abs(), rate)) { //奖池剩余金额的绝对值小于手续费，需要补回奖池里的金额
							log.info("用户{} 充值{} 实际到账金额{}，从活动奖池中补回手续费{}，奖池剩余不足{}，需从中扣除{}",
									record.getPlayerId(), record.getAmount(), actualAmount, rate, promotions.getPrizePool(), promotions.getPrizePool());
							record.setActualAmount(NumberUtil.sub(actualAmount, promotions.getPrizePool()));
						} else {
							log.info("用户{} 充值{} 实际到账金额{}，从活动奖池中补回手续费{}，奖池剩余不足{}，需从中扣除{}",
									record.getPlayerId(), record.getAmount(), actualAmount, rate, promotions.getPrizePool(), rate);
							record.setActualAmount(NumberUtil.sub(actualAmount, rate));
						}
					} else {
						log.info("用户{} 充值{} 实际到账金额{}，从活动奖池中补回手续费{}，奖池剩余{}",
								record.getPlayerId(), record.getAmount(), actualAmount, rate, promotions.getPrizePool());
						record.setActualAmount(actualAmount);
					}
					recordMapper.updateById(record);
				}
			}
		}
		// 给玩家添加余额
		FrontUser frontUser = new FrontUser();
		LambdaUpdateWrapper<FrontUser> updateWrapper = Wrappers.lambdaUpdate();
		updateWrapper.setSql("balance = balance + " + record.getActualAmount())
				.eq(FrontUser::getId, record.getPlayerId());
		frontUserMapper.update(frontUser, updateWrapper);
		//添加交易记录
		FundDetail fundDetail = new FundDetail();
		fundDetail.setPlayerAccount(record.getPlayerName());
		fundDetail.setGoods("玩家充值");
		fundDetail.setAmount(record.getActualAmount());
		fundDetail.setOrderId(record.getId());
		fundDetail.setUid(record.getUid());
		fundDetail.setIp(record.getIp());
		fundDetail.setPlayerId(record.getPlayerId());
		fundDetail.setBalance(record.getBalance());
		fundDetail.setDealTime(LocalDateTime.now());
		fundDetail.setPaySolution(channel.getType().getDescription() + "#" + channel.getName());
		fundDetail.setChannelShare(record.getAmount().subtract(record.getActualAmount()));
		fundDetail.setAlias(alias);
		fundDetail.setType(2);
		fundDetailMapper.insert(fundDetail);*/
		processRecord(record, channel, alias);
	}

	@Async("taskExecutor")
	public void processOrder(Record record, BackPaymentChannel channel, String alias) {
		processRecord(record, channel, alias);
	}

	@Transactional(rollbackFor = Exception.class)
	public void processRecord(Record record, BackPaymentChannel channel, String alias) {
		/*if (channel.getType() == RechargeSolution.UPAY_PAYMENT) {
			Promotions promotions = promotionsService.getOne(Wrappers.<Promotions>lambdaQuery()
					.eq(Promotions::getKey, PromotionsConstant.PRIZE_POOL));
			if (promotions.getEnable() && NumberUtil.isGreater(promotions.getPrizePool(), BigDecimal.ZERO)) {
				BigDecimal rate = record.getAmount().subtract(record.getActualAmount());
				boolean isSuccess = promotionsService.update(Wrappers.<Promotions>lambdaUpdate()
						.setSql("prize_pool = prize_pool - " + rate)
						.eq(Promotions::getId, 1)
						.gt(Promotions::getPrizePool, BigDecimal.ZERO));
				if (isSuccess) {
					promotions = promotionsService.getOne(Wrappers.<Promotions>lambdaQuery()
							.eq(Promotions::getKey, PromotionsConstant.PRIZE_POOL));
					BigDecimal actualAmount = NumberUtil.add(record.getActualAmount(), rate);
					if (NumberUtil.isLess(promotions.getPrizePool(), BigDecimal.ZERO)) { //奖池金额小于0
						if (NumberUtil.isLess(promotions.getPrizePool().abs(), rate)) { //奖池剩余金额的绝对值小于手续费，需要补回奖池里的金额
							log.info("用户{} 充值{} 实际到账金额{}，从活动奖池中补回手续费{}，奖池剩余不足{}，需从中扣除{}",
									record.getPlayerId(), record.getAmount(), actualAmount, rate, promotions.getPrizePool(), promotions.getPrizePool());
							record.setActualAmount(NumberUtil.sub(actualAmount, promotions.getPrizePool()));
						} else {
							log.info("用户{} 充值{} 实际到账金额{}，从活动奖池中补回手续费{}，奖池剩余不足{}，需从中扣除{}",
									record.getPlayerId(), record.getAmount(), actualAmount, rate, promotions.getPrizePool(), rate);
							record.setActualAmount(NumberUtil.sub(actualAmount, rate));
						}
					} else {
						log.info("用户{} 充值{} 实际到账金额{}，从活动奖池中补回手续费{}，奖池剩余{}",
								record.getPlayerId(), record.getAmount(), actualAmount, rate, promotions.getPrizePool());
						record.setActualAmount(actualAmount);
					}
					recordMapper.updateById(record);
				}
			}
		}*/

		if (channel.getChannel() == 1) {
			Promotions promotions = promotionsService.getOne(Wrappers.<Promotions>lambdaQuery()
					.eq(Promotions::getKey, PromotionsConstant.APP_REWARD));
			log.info("查询活动记录：{}", promotions);
			if (promotions != null
					&& promotions.getEnable()
					&& NumberUtil.isGreater(promotions.getPrizePool(), BigDecimal.ZERO)) {
				BigDecimal reward = reward(record);
				if (NumberUtil.isGreater(reward, BigDecimal.ZERO)) {
					record.setActualAmount(record.getActualAmount().add(reward));
					recordMapper.updateById(record);
				}
			}
		}
		// 给玩家添加余额
		FrontUser frontUser = new FrontUser();
		LambdaUpdateWrapper<FrontUser> updateWrapper = Wrappers.lambdaUpdate();
		updateWrapper.setSql("balance = balance + " + record.getActualAmount())
				.eq(FrontUser::getId, record.getPlayerId());
		frontUserMapper.update(frontUser, updateWrapper);
		//添加交易记录
		FundDetail fundDetail = new FundDetail();
		fundDetail.setPlayerAccount(record.getPlayerName());
		fundDetail.setGoods("玩家充值");
		fundDetail.setAmount(record.getActualAmount());
		fundDetail.setOrderId(record.getId());
		fundDetail.setUid(record.getUid());
		fundDetail.setIp(record.getIp());
		fundDetail.setPlayerId(record.getPlayerId());
		fundDetail.setBalance(record.getBalance());
		fundDetail.setDealTime(LocalDateTime.now());
		fundDetail.setPaySolution(channel.getType().getDescription() + "#" + channel.getName());
		fundDetail.setChannelShare(record.getAmount().subtract(record.getActualAmount()));
		fundDetail.setAlias(alias);
		fundDetail.setType(2);
		fundDetailMapper.insert(fundDetail);

	}

	private BigDecimal calculationReward(Record record, BigDecimal reward) {
		boolean isSuccess = promotionsService.update(Wrappers.<Promotions>lambdaUpdate()
				.setSql("prize_pool = prize_pool - " + reward)
				.eq(Promotions::getKey, PromotionsConstant.APP_REWARD)
				.gt(Promotions::getPrizePool, BigDecimal.ZERO));
		BigDecimal actualReward = BigDecimal.ZERO;
		if (isSuccess) {
			//扣款成功
			//如果扣款完是负数
			//则不给奖励
			//如果扣款完负数比奖励低，则把剩余的给了
			//不是负数则正常给
			Promotions promotions = promotionsService.getOne(Wrappers.<Promotions>lambdaQuery()
					.eq(Promotions::getKey, PromotionsConstant.APP_REWARD));
			if (promotions == null) {
				return actualReward;
			}
			if (NumberUtil.isLess(promotions.getPrizePool(), BigDecimal.ZERO)) { //奖池金额小于0
				if (!NumberUtil.isLess(promotions.getPrizePool().abs(), reward)) { //奖池剩余金额的绝对值小于手续费，需要补回奖池里的金额
					actualReward = reward.subtract(promotions.getPrizePool().abs());
					log.info("用户{} 充值{} 实际到账金额{}，从活动奖池奖励{}，奖池剩余不足{}，实际奖励{}",
							record.getPlayerId(), record.getAmount(), record.getActualAmount(), reward, promotions.getPrizePool(), actualReward);
				}
			} else {
				log.info("用户{} 充值{} 实际到账金额{}，从活动奖池中补回手续费{}，奖池剩余{}",
						record.getPlayerId(), record.getAmount(), record.getActualAmount(), reward, promotions.getPrizePool());
				actualReward = reward;
			}
		}
		return actualReward;
	}

	public BigDecimal reward(Record record) {
		List<PrizeRule> rules = prizeRuleMapper.selectList(Wrappers.<PrizeRule>lambdaQuery().eq(PrizeRule::getKey, RECORD_REWARD_RATE));
		if (rules.isEmpty()) { //中奖规则为控股你
			log.info("中奖规则为空");
			return BigDecimal.ZERO;
		}
		PrizeRule prize = PrizeRule.pay(rules);
		if (prize == null) { //未获得奖品
			log.info("未获取中奖规则");
			return BigDecimal.ZERO;
		}
		String p = prize.getPrize();
		if (StrUtil.isBlank(p)) { //奖品内没设置值
			log.info("未获取奖品");
			return BigDecimal.ZERO;
		}
		String[] s = p.split(",");
		if (s.length < 2 || !NumberUtil.isNumber(s[0]) || !NumberUtil.isNumber(s[1])) { //奖品错误
			log.info("奖品错误");
			return BigDecimal.ZERO;
		}
		BigDecimal charges = record.getAmount().subtract(record.getActualAmount());
		BigDecimal rateMin = charges.multiply(NumberUtil.toBigDecimal(s[0]));
		BigDecimal rateMax = charges.multiply(NumberUtil.toBigDecimal(s[1]));
		BigDecimal reward = RandomUtil.randomBigDecimal(rateMin, rateMax).setScale(2, RoundingMode.HALF_UP);
		BigDecimal actualReward = calculationReward(record, reward);
		if (NumberUtil.isLessOrEqual(actualReward, BigDecimal.ZERO)) {
			return BigDecimal.ZERO;
		}
		OrderReward r = new OrderReward();
		r.setAmount(actualReward);
		r.setUserId(record.getPlayerId());
		r.setOrderId(record.getId());
		r.setType(0);
		rewardMapper.insert(r);
		return actualReward;
	}

}
